﻿using System;
using System.ComponentModel;
using System.Configuration;

namespace AppEszköz.Config.Utility
{
    /// <summary>
    /// Provides methods for accessing the registry and App.Config file in a strongly-typed manner
    /// </summary> 
    public static class ConfigurationReader
    {
        /// <summary>
        /// Returns a registry configuration value of the specified type or throws an exception
        /// if the configuration value cannot be read
        /// </summary>
        /// <typeparam name="T">Type of configuration value to return</typeparam>
        /// <param name="group">Registry group under your application's registry entry in which your config value resides</param>
        /// <param name="key">Name of the registry key inside your group</param>
        /// <returns></returns>
        public static T GetRegistryConfig<T>(string group, string key)
        {
            return GetRegistryConfig<T>(group, key, true);
        }

        /// <summary>
        /// Returns a registry configuration value of the specified type
        /// </summary>
        /// <typeparam name="T">Type of configuration value to return</typeparam>
        /// <param name="group">Registry group under your application's registry entry in which your config value resides</param>
        /// <param name="key">Name of the registry key inside your group</param>
        /// <param name="isRequired">
        /// If true, an exception will be thrown if the key cannot be found or is the wrong type.
        /// Otherwise the default value for the supplied data type will be returned.
        /// </param>
        /// <returns></returns>
        public static T GetRegistryConfig<T>(string group, string key, bool isRequired)
        {
            try
            {
                var converter = TypeDescriptor.GetConverter(typeof(T));

                var configValue = ConfigRegistryHelper.GetConfig(ConfigHelper.GetConfig("General.ApplicationName"), group, key);

                return (T)converter.ConvertFrom(configValue);
            }
            catch (Exception ex)
            {
                if (isRequired)
                {
                    throw new ConfigurationErrorsException("Error finding or casting registry configuration value. group= " + group ?? "null" + ", key=" + key ?? "null", ex);
                }
                return default(T);
            }
        }

        /// <summary>
        /// Attempts to retrieve the config value with the specified key from the App.Config file
        /// Throws an exception if the attempt fails
        /// </summary>
        /// <typeparam name="T">Type of object to cast to and return</typeparam>
        /// <param name="key">Key to locate</param>
        /// <returns></returns>
        public static T GetAppConfig<T>(string key)
        {
            return GetAppConfig<T>(key, true);
        }

        /// <summary>
        /// Attempts to retrieve the config value with the specified key from the App.Config file
        /// </summary>
        /// <typeparam name="T">Type of object to cast to and return</typeparam>
        /// <param name="key">Key to locate</param>
        /// <param name="isRequired">
        /// If true, an exception will be thrown if the key cannot be found or is the wrong type.
        /// Otherwise the default value for the supplied data type will be returned.
        /// </param>
        /// <returns></returns>
        public static T GetAppConfig<T>(string key, bool isRequired)
        {
            try
            {
                var converter = TypeDescriptor.GetConverter(typeof(T));

                var configValue = ConfigurationManager.AppSettings.Get(key);

                return (T)converter.ConvertFrom(configValue);
            }
            catch (Exception ex)
            {
                if (isRequired)
                {
                    throw new ConfigurationErrorsException("Missing key=" + key ?? "null", ex);
                }
                return default(T);
            }
        }
    }
}